﻿using Microsoft.SqlServer.TransactSql.ScriptDom;

using static Microsoft.SqlServer.TransactSql.ScriptDom.TSqlTokenType;
namespace zijian666.Data;

/// <summary>
/// 将 SQL 中的 `xxx = NULL` 为 `xxx IS NULL`
/// </summary>
internal static class TSqlParseExtensions
{
    public static IList<TSqlParserToken> ParseSqlTokens(this string sql)
    {
        ArgumentNullException.ThrowIfNull(sql);
        var parser = TSqlParser.CreateParser(SqlVersion.Sql150, true);
        using var reader = new StringReader(sql);
        var tokens = parser.GetTokenStream(reader, out var errors);
        if (errors.Count > 0)
        {
            return [];
        }
        return tokens;
    }

    /// <summary>
    /// 前进下到一个分号
    /// </summary>
    private static void SkipToSemicolon(IList<TSqlParserToken> tokens, ref int index)
    {
        for (; index < tokens.Count; index++)
        {
            if (tokens[index].TokenType is Semicolon)
            {
                return;
            }
        }
    }
    /// <summary>
    /// 跳过括号内的内容
    /// </summary>
    private static void SkipParenthesis(IList<TSqlParserToken> tokens, ref int index)
    {
        for (; index < tokens.Count; index++)
        {
            if (tokens[index].TokenType is LeftParenthesis)
            {
                index++;
                SkipParenthesis(tokens, ref index);
            }
            else if (tokens[index].TokenType is RightParenthesis)
            {
                return;
            }
        }
    }

    // 跳过空白和注释
    private static void SkipWhiteSpace(IList<TSqlParserToken> tokens, ref int index)
    {
        for (; index < tokens.Count; index++)
        {
            if (tokens[index].TokenType is WhiteSpace or MultilineComment or SingleLineComment)
            {
                continue;
            }
            return;
        }
    }

    public static bool IsSelect(this IList<TSqlParserToken> tokens)
    {
        if (tokens is null)
        {
            return false;
        }



        for (int i = 0; i < tokens.Count; i++)
        {
            var token = tokens[i];

            // 跳过这些类型的token
            if (token.TokenType is WhiteSpace or MultilineComment or SingleLineComment or Variable or Semicolon)
            {
                continue;
            }

            // 检查是否是DECLARE语句
            if (token.TokenType is Declare)
            {
                SkipToSemicolon(tokens, ref i);
                continue;
            }

            // 如果遇到SET语句也需要跳过
            if (token.TokenType is Set)
            {
                SkipToSemicolon(tokens, ref i);
                continue;
            }

            // 找到第一个非特殊token后判断是否是SELECT
            if (token.TokenType is Select)
            {
                return true;
            }
            // 如果第一个有效token不是SELECT，则不是SELECT语句
            return false;
        }
        return false;
    }

    public static (TSqlParserToken? begin, TSqlParserToken? end) GetTopSelectColumn(this IList<TSqlParserToken> tokens)
    {
        ArgumentNullException.ThrowIfNull(tokens);
        if (!IsSelect(tokens))
        {
            return (null, null);
        }
        // 从头开始遍历tokens来寻找最外层的SELECT
        for (int i = 0; i < tokens.Count; i++)
        {
            var token = tokens[i];
            // 处理括号层级
            if (token.TokenType is TSqlTokenType.LeftParenthesis)
            {
                i++;
                SkipParenthesis(tokens, ref i);
                continue;
            }
            // 处理分号
            if (token.TokenType is TSqlTokenType.Semicolon)
            {
                return (null, null);
            }
            // 处理SELECT
            if (token.TokenType == TSqlTokenType.Select)
            {
                var selectStart = tokens[i + 1];
                // 继续向后遍历直到遇到 FROM 子句
                for (int j = i + 1; j < tokens.Count; j++)
                {
                    var currentToken = tokens[j];
                    if (currentToken.TokenType is From)
                    {
                        return (selectStart, tokens[j - 1]);
                    }
                }
            }
        }
        return (null, null);

    }

    public static (TSqlParserToken? begin, TSqlParserToken? end) GetTopOrderBy(this IList<TSqlParserToken> tokens)
    {
        ArgumentNullException.ThrowIfNull(tokens);
        if (!IsSelect(tokens))
        {
            return (null, null);
        }


        // 从头开始遍历tokens来寻找最外层的ORDER BY
        for (int i = 0; i < tokens.Count; i++)
        {
            var token = tokens[i];

            // 处理括号层级
            if (token.TokenType is TSqlTokenType.LeftParenthesis)
            {
                i++;
                SkipParenthesis(tokens, ref i);
                continue;
            }
            // 处理分号
            if (token.TokenType is TSqlTokenType.Semicolon)
            {
                return (null, null);
            }

            // 处理order by
            if (token.TokenType == TSqlTokenType.Order)
            {
                i++;
                SkipWhiteSpace(tokens, ref i);
                if (tokens[i].TokenType == TSqlTokenType.By)
                {
                    var orderByStart = token;
                    // 继续向后遍历直到遇到以下情况之一：OFFSET 子句、FOR 子句、语句结束(分号)、tokens结束
                    for (int j = i + 1; j < tokens.Count; j++)
                    {
                        var currentToken = tokens[j];
                        // 如果到达tokens末尾
                        if (j == tokens.Count - 1)
                        {
                            return (orderByStart, currentToken);
                        }
                        if (currentToken.TokenType is EndOfFile or For or Semicolon
                            || currentToken.Text.Equals("limit", StringComparison.OrdinalIgnoreCase)
                            || currentToken.Text.Equals("offset", StringComparison.OrdinalIgnoreCase))
                        {
                            return (orderByStart, tokens[j - 1]);
                        }
                    }
                }
            }
        }

        return (null, null);
    }

    /// <summary>
    /// 去掉末尾的分号
    /// </summary>
    /// <param name="sql"></param>
    /// <returns></returns>
    public static string TrimSemicolon(this string sql)
    {
        if (string.IsNullOrWhiteSpace(sql))
        {
            return sql;
        }
        return sql.TrimEnd([';', ' ', '\r', '\n', '\t']);
    }
}